#include "utils.h"

#include "CNeuron.h"

/*----------------------------------------------------------------------------*/


CNeuronBase::CNeuronBase( int _inputsNum )
	:	m_resValue( 0.0 )
	,	m_localError( 0.0 )
{	
	m_weights.resize( _inputsNum + 1 );
	m_weightedError.resize( _inputsNum + 1, 0.0 );	
	CNeuronBase::InitWeights();	
}


/*----------------------------------------------------------------------------*/


CNeuronBase::CNeuronBase( std::ifstream& _file )
	:	m_resValue( 0.0 )
	,	m_localError( 0.0 )
{
	int weightsSize;
	_file.read( (char*)&weightsSize, sizeof( int ) );
	m_weights.resize( weightsSize );
	m_weightedError.resize( weightsSize, 0.0 );
	for ( int i = 0; i < weightsSize; i++ )
	{
		double weight = 0.0;
		_file.read( (char*)&weight, sizeof( double ) );
		m_weights[i] = weight;
	}
}

/*----------------------------------------------------------------------------*/


CNeuronBase::~CNeuronBase()
{
}


/*----------------------------------------------------------------------------*/


double CNeuronBase::CalculateOutputValue( const DoubleV& _inputValues )
{
	double wSum = m_weights[0];
	for( size_t i = 1; i < m_weights.size(); i++ )
	{
		wSum += _inputValues[i-1] * m_weights[i];			
	}
	wSum /= m_weights.size();
	m_resValue = ActivationFunc( wSum );
	return m_resValue;
}


/*----------------------------------------------------------------------------*/


double CNeuronBase::GetWeightedError( int _weightNum )
{
	return m_weightedError[ _weightNum ];
}


/*----------------------------------------------------------------------------*/


void CNeuronBase::CalcNewWeights( double _speed, const DoubleV& _inputValues )
{
	m_weights[0] = m_weights[0] + _speed * m_localError * 1.0;
	for( size_t i = 1; i < m_weights.size(); i++ )
	{
		m_weights[i] = m_weights[i] + _speed * m_localError * _inputValues[i-1];
	}
}


/*----------------------------------------------------------------------------*/


void CNeuronBase::InitWeights()
{	
	for( size_t i = 0; i < m_weights.size(); i++ )
	{	
		m_weights[i] = ( ( rand() % 50 ) + 1 ) / 100.0;
	}
}


/*----------------------------------------------------------------------------*/


void CNeuronBase::CalcWeightedErrors()
{
	for( size_t i = 0; i < m_weights.size(); i++ )
	{
		m_weightedError[i] = m_weights[i] * m_localError;		
	}
}


/*----------------------------------------------------------------------------*/


double CNeuronBase::ActivationFunc( double _value )
{	
	return ( 1.0 / ( 1.0 + exp( -_value ) ) );
}


/*----------------------------------------------------------------------------*/


void CNeuronBase::PrintWeights()
{
	for( size_t i = 0; i < m_weights.size(); i++ )
	{
		printf( "\n>\t\tw%d = %f", i, m_weights[i] );
	}
}


/*----------------------------------------------------------------------------*/


void CNeuronBase::PrintResValue()
{
	printf( "\n>\t\ty = %f", m_resValue );
}


/*----------------------------------------------------------------------------*/


void CNeuronBase::PrintError()
{
	printf( "\n>\t\tLocal error = %f", m_localError );
}


/*----------------------------------------------------------------------------*/


void CNeuronBase::PrintWeError()
{
	for( size_t i = 0; i < m_weightedError.size(); i++ )
	{
		printf( "\n>\t\tBackError%d = %f", i, m_weightedError[i] );
	}	
}


/*----------------------------------------------------------------------------*/


void CNeuronBase::SaveToFile( std::ofstream& _file )
{
	size_t weigtsSize = m_weights.size();
	_file.write( (char*)&weigtsSize, sizeof( size_t ) );
	for ( size_t i = 0; i < weigtsSize; i++ )
	{
		double weight = m_weights[i];
		_file.write( (char*)&weight, sizeof( double ) );
	}
}


/*----------------------------------------------------------------------------*/


CNeuron::CNeuron( int _inputsNum )
	:	CNeuronBase( _inputsNum )
{
}


/*----------------------------------------------------------------------------*/


CNeuron::CNeuron( std::ifstream& _file )
	:	CNeuronBase( _file )
{
}


/*----------------------------------------------------------------------------*/


void CNeuron::CalcLocalError( double _backError )
{
	// calculating local error
	m_localError = m_resValue * ( 1.0 - m_resValue ) * _backError;
	// calculating weighted error
	CNeuronBase::CalcWeightedErrors();
}


/*----------------------------------------------------------------------------*/


CNeuronLast::CNeuronLast( int _inputsNum )
	:	CNeuronBase( _inputsNum )
{
}


/*----------------------------------------------------------------------------*/


CNeuronLast::CNeuronLast( std::ifstream& _file )
	:	CNeuronBase( _file )
{

}


/*----------------------------------------------------------------------------*/


void CNeuronLast::CalcLocalError( double _desiredResult )
{
	// calculating local error
	m_localError = ( _desiredResult - m_resValue ) * m_resValue * ( 1.0 - m_resValue );
	// calculating weighted error
	CNeuronBase::CalcWeightedErrors();
}


/*----------------------------------------------------------------------------*/
